// copyright (c) 2001-2002, RealNetworks, Inc. 
// depends on xblib.js
function TOCTree ( winTOC, winContent )
{

	if ( !TOCTree.bInitialized )
		TOCTree.initTOCTreeClass();
	// only one TOCTree per window allowed
	if ( winTOC && winTOC.TheTOCTree )
	{
		return winTOC.TheTOCTree ;
	}
	this.m_winTOC = winTOC;
	this.m_winContent = winContent;
	this.m_docTOC = null;
	/*************************************
		TOCTree option and default values
	*************************************/
	this.m_bSyncTOCWithContent = false ;
	this.m_ContentHREFToTOCLinkMap = null ;
	this.m_bHiliteCurLink = false ;
	this.m_hiColor = "";
	this.m_hiBGColor = "green";
	this.m_imgOpenSrc = "" ;
	this.m_imgCloseSrc = "" ;
	this.m_imgLeafSrc = "" ;
	// how often to check the content frame for content changes 
	// that we want the TOC to sync with
	this.m_nSyncInterval = 0;	
	// various magic numbers for Nav4
	this.m_nYOffset = 0 ;		// the Y pos for the first TOC link - we have to absolutly position it in Nav4
	// in Nav4 we can't read a folder's className attribute so we have to infer its level in the
	// hierarchy by comparing its "left" attribute to the following:
	this.m_nIndentDelta = 10 ;	// no. of pixels each class is indented - should match stylesheet
	this.m_nXOffset = 18;		// no. of pixels root level folder is indented - should match stylesheet
	this.m_basePath = "";
	/*************************************
		TOCTree state member variables
	*************************************/
	this.m_bInitialized = false ;
	this.m_curFolderID = -1 ;		// the current folder whose content is displayed in the content frame
	this.m_curHiliteFolderID = "" ;	// the folder currently being hilighted (usually the same as the curFolder)
	this.m_curBODYLocation = "";	// the href of the content in the content frame
	//this.m_origClickHandler = null ;
	this.m_bDoArrowKeyNav = true ;
	this.m_origKeyDownHandler = null ;
	this.m_origKeyPressHandler = null;
	this.m_syncTimeoutId = null ;
	/*************************************
		TOCTree data member variables
	*************************************/
	this.m_imgOpen = null;
	this.m_imgClose = null;
	// keep a global refererence to this class instance so that 
	// we can pass instance methods to setTimeout()
	if ( this.m_winTOC )
	{
		this.m_winTOC.TheTOCTree = this;
	}
	return this;
}	// TOCTree
TOCTree.HiliteId = "THEHILITE";
TOCTree.initTOCTreeClass = function ()
{

	if ( ! isXblibInit ) xblibInit();
	// setup browser specific functionality
	if ( isNav4 )
	{
		TOCTree.prototype.applyHilite = applyHilite_Nav4;
		TOCTree.prototype.removeHilite = removeHilite_Nav4;
	}
	else if ( isIE4 )
	{
		TOCTree.prototype.applyHilite = applyHilite_IE4;
		TOCTree.prototype.removeHilite = removeHilite_IE4;
	}
	else
	{
		TOCTree.prototype.applyHilite = applyHilite_W3C;
		TOCTree.prototype.removeHilite = removeHilite_W3C;
	}
	TOCTree.bInitialized = true ;
}
TOCTree.initTOCTreeClass();
TOCTree.prototype.initialize = function ()
{

	this.m_docTOC = this.m_winTOC.document;
	this.m_imgOpen = new Image(); 
	this.m_imgClose = new Image(); 
	this.m_imgOpen.src = this.m_basePath + this.m_imgOpenSrc ;
	this.m_imgClose.src = this.m_basePath + this.m_imgCloseSrc ;
	this.m_bInitialized = true ;
	//because of Mozilla Bug 49980 (as of 4/11/01) we can't use anonymous functions
	//as event handlers - so we assign the instance method call generated by
	// getInstanceEventHandler() to a variable of TOC window...
	/*
	this.m_winTOC._onDocClick = getInstanceEventHandler( this, "onDocClick" );
	//... and then hook it in as the document's click handler
	this.m_origClickHandler = addEvent( this.m_docTOC, "click", 
		this.m_winTOC._onDocClick, 1, (isNav4 ? Event.CLICK : null) );
	*/
	// instead of this:
	/*	
	this.m_origClickHandler = addEvent( this.m_docTOC, "click", 
		getInstanceEventHandler( this, "onDocClick" ), 
		1, (isNav4 ? Event.CLICK : null) );
	*/
	// do the same for the (arrow) key handlers
	if ( this.m_bDoArrowKeyNav )
	{
		this.m_winTOC._onDocKeyDown = getInstanceEventHandler( this, "onDocKeyDown" );
		this.m_origKeyDownHandler = addEvent( this.m_docTOC, "keydown", 
			this.m_winTOC._onDocKeyDown, 1, (isNav4 ? Event.KEYDOWN : null) );
		// kill arrow keypress events for Nav6 - otherwise the window is scrolled (as well as moving
		// the selection
		if ( isMoz5 )
		{
			// do the same for the (arrow) key handler
			this.m_winTOC._onDocKeyPress = getInstanceEventHandler( this, "onDocKeyPress" );
			this.m_origKeyPressHandler = addEvent( this.m_docTOC, "keypress", 
				this.m_winTOC._onDocKeyPress, 1 );
		}
	}
	// work-around for navigator scrambling the TOC frame when it's resized: force a reload
	if ( isNav4 )
	{
		this.m_winTOC.captureEvents( Event.RESIZE );
		this.m_winTOC.onresize = function(){location.reload();return false;};
	}
	if ( isNav4 )
	{
		// adjust the Y coord and display every 'level0' folder
		var nextY =	this.m_nYOffset ;
		var folder = this.getFolderFromID( "z0" );
		var exposedHeight = this.m_nYOffset + folder.clip.height ; // use the height of one folder as a buffer space
		var iter = new FolderIter( folder );
		while ( folder )
		{
			if ( iter.curLevel() == this.m_nXOffset )
			{
				folder.pageY = nextY ;
				folder.visibility = "show";
				nextY += folder.document.height ;
				exposedHeight += folder.clip.height ;
			}
			folder = iter.getNext();
		}

		// adjust the window size so that scroll bars adjust as needed
		this.m_docTOC.height = exposedHeight;

		// cache a pointer to the HILITE DIV
		if ( this.m_bHiliteCurLink )
		{
			this.m_hiliteDiv = this.m_docTOC[ TOCTree.HiliteId ];
			if ( ! this.m_hiliteDiv )
			{
				alert( "HILITING TURNED ON BUT NO HILITER WAS FOUND - insert call to TOCTree.createHiliter inside <BODY>" ); 
			}
		}
	}
	if ( this.m_bSyncTOCWithContent )
	{
		this.m_syncTimeoutId = this.m_winTOC.setTimeout( "TheTOCTree.syncTOC()", this.m_nSyncInterval );
	}

}	// initialize ()
// this is a class method - because it has to be called while the document is loading
// and objects are typically not instantiated until the document is finished loading.
TOCTree.createHiliter = function ( docObj, imgSrc )
{
	if ( isNav4 )
	{
		docObj.write( '<layer style="position:absolute;left:0;padding:0;margin:0;width=100%;visibility:hidden;" id="' + TOCTree.HiliteId + '"><IMG SRC="' + imgSrc + '"></layer>' );
		var div = docObj[ TOCTree.HiliteId ];
		if ( div )
		{
			div.visibility = "hidden" ;
		}
	}
}
TOCTree.prototype.onError = function ( msg, url, line )
{
	// if we're trying to acces the location of the body frame and it comes from 
	// another domain, then trap the error here
	if ( isMoz5 ) return true ;
	if ( -1 != msg.search( /access disallowed|permission denied/i ) )
	{
		this.m_syncTimeoutId = this.m_winTOC.setTimeout( "TheTOCTree.syncTOC()", this.m_nSyncInterval );
		return true ;
	}
	alert( "JavaScript Error:\n" + msg + "\n\nIn file:\t" + url + "\n\nLine No.:\t" + line );
	return true ;
}
//window.onerror = onError;
TOCTree.prototype.hiliteFolder = function ( folder )
{
	if ( !(folder && this.m_bHiliteCurLink) ) return ;

	// already hilighted
	if ( this.isFolderVisible( folder ) && 
		 (this.m_curHiliteFolderID == folder.id) )
	{

		return ;
	}
	var curHiliteFolder = this.getFolderFromID( this.m_curHiliteFolderID );
	// unhilite the currently hilited folder
	if ( curHiliteFolder )
	{
		this.removeHilite( curHiliteFolder );
		this.m_curHiliteFolderID = "" ;
	}
	// hilite folder - if it isn't visible find the first ancestor that is
	var iter = new FolderIter( folder );
	while ( folder )
	{
		if ( this.isFolderVisible( folder ) )
			break;
		folder = iter.getParent();
	}
	if ( folder )
	{
		this.applyHilite( folder );			
		this.m_curHiliteFolderID = folder.id ;
	}
	else{}
}	// hiliteFolder 
function applyHilite_IE4 ( folder )
{
	if ( this.m_hiColor )
		folder.children[ folder.children.length - 1 ].style.color = this.m_hiColor ;
	if ( this.m_hiBGColor )
		folder.children[ folder.children.length - 1 ].style.backgroundColor = this.m_hiBGColor ;
}	// applyHilite_IE4
function applyHilite_Nav4 ( folder )
{
	this.m_hiliteDiv.visibility = "show" ;
	this.m_hiliteDiv.moveBelow( folder );
	this.m_hiliteDiv.moveTo( 0, folder.top );
}	// applyHilite_Nav4
function applyHilite_W3C ( folder )
{
	if ( this.m_hiColor )
		folder.lastChild.style.color = this.m_hiColor ;
	if ( this.m_hiBGColor )
		folder.lastChild.style.backgroundColor = this.m_hiBGColor ;
}	// applyHilite_W3C
function removeHilite_IE4 ( folder )
{
	folder.children[ folder.children.length - 1 ].style.color = "" ;
	folder.children[ folder.children.length - 1 ].style.backgroundColor = "" ;
}	// removeHilite_IE4
function removeHilite_Nav4 ( folder )
{
	this.m_hiliteDiv.visibility = "hide" ;
}	// removeHilite_Nav4
function removeHilite_W3C ( folder )
{
	folder.lastChild.style.color = "" ;
	folder.lastChild.style.backgroundColor = "" ;
}	// removeHilite_W3C
//move back through the layers, exposing them until a layer is reached 
// that is exposed already or we hit the root layer
TOCTree.prototype.exposeFolder = function ( folder )
{
	if ( ! folder ) return ;
	if ( ! this.isFolderVisible( folder ) )
	{
		var iter = new FolderIter( folder );
		var parentFolder = iter.getParent();
		while ( parentFolder )
		{
			if( ! this.isFolderOpen( parentFolder ) )
			{
				this.tf( null, parentFolder );
			}
			parentFolder = iter.getParent();
		}
	}
	if ( ! isElemInView( folder, this.m_winTOC ) )
	{
		scrollVertToElem( folder, this.m_winTOC );		
	}
}
TOCTree.prototype.isFolderOpen = function ( folder )
{
	if ( isNav4 )
	{
		return ( -1 != folder.document.images[ 0 ].src.indexOf( this.m_imgOpenSrc ) );
	}
	else
	{
		return (1 == this.getFolderStatus( folder ));
	}
}
TOCTree.prototype.getFolderStatus = function ( folder )
{
	if ( folder.folderStatus == null )
	{
		// folder status is determined by the srcname of img icon
		// the img icon is a child or 'grandchild' of the folder:
		// <DIV><A href="tf()"><IMG></A> or
		// <DIV><A><IMG></A> (leaf icons - note empty <A> tag) 
		var imgSrc = "";
		if ( isIE4 )
		{
			// if first child is an image then this is a leaf folder (can't open or close)
			if ( ("IMG" == folder.children[ 0 ].tagName) ||
				 (("A"  == folder.children[ 0 ].tagName) &&
				  (! folder.children[ 0 ].href)) )
			{
				return (folder.folderStatus = 0);
			}
			else	// look at the grandchild
			{
				imgSrc = folder.children[ 0 ][ 0 ].src ;
			}
		}
		else
		{
			// if first child is an image then this is a leaf folder (can't open or close)
			if ( ("IMG" == folder.firstChild.tagName) ||
				 (("A"  == folder.firstChild.tagName) &&
				  (! folder.firstChild.href)) )
			{
				return (folder.folderStatus = 0);
			}
			else	// look at the grandchild
			{
				imgSrc = folder.firstChild.firstChild.src ;
			}
		}
		if ( -1 != imgSrc.indexOf( this.m_imgOpenSrc )  )
		{
			folder.folderStatus = 1;
		}
		else if ( -1 != imgSrc.indexOf( this.m_imgCloseSrc ) )
		{
			folder.folderStatus = -1;
		}
	}
	return folder.folderStatus;	
}
TOCTree.prototype.isFolderClosed = function ( folder )
{
	if ( isNav4 )
	{
		return ( -1 != folder.document.images[ 0 ].src.indexOf( this.m_imgCloseSrc ) );
	}
	else
	{
		return  (-1 == this.getFolderStatus( folder ));
	}
}
TOCTree.prototype.isLeafFolder = function ( folder )
{
	if ( isNav4 )
	{
		return ( -1 != folder.document.images[ 0 ].src.indexOf( this.m_imgLeafSrc ) );
	}
	else
	{
		return (0 == this.getFolderStatus( folder ));
	}
}
TOCTree.prototype.openFolder = function ( folder )
{
	var img ;
	if ( isNav4 )
	{
		img = folder.document.images[ 0 ];
	}
	else
	{
	 	folder.folderStatus = 1;
		if ( isIE4 )
		{
			img = folder.children[ 0 ][ 0 ];
		}
		else
		{
			img = folder.firstChild.firstChild;
		}
	}
	if ( img )
		img.src = this.m_imgOpen.src ;
}
TOCTree.prototype.closeFolder = function ( folder )
{
	var img ;
	if ( isNav4 )
	{
		img = folder.document.images[ 0 ];
	}
	else
	{
	 	folder.folderStatus = -1;
		if ( isIE4 )
		{
			img = folder.children[ 0 ][ 0 ];
		}
		else
		{
			img = folder.firstChild.firstChild;
		}
	}
	if ( img )
		img.src = this.m_imgClose.src ;
}
TOCTree.prototype.hideFolder = function ( folder )
{
	if ( isNav4 )
	{
		folder.visibility = "hide" ;	
	}
	else
	{
		folder.style.display = "none";
	}
}
TOCTree.prototype.isFolderVisible = function ( folder )
{
	if ( isNav4 )
	{
		return ( "show" == folder.visibility );
	}
	else
	{
		// level0 folders are always visible - BUT
		// the display property can be == "" so just
		// check the classname
		if ( 0 == parseInt( folder.className.slice(1) ) )
		{
			return true ;
		}
		return ( "block" == folder.style.display );
	}
}
TOCTree.prototype.showFolder = function ( folder )
{
	if ( isNav4 )
	{
		folder.visibility = "show" ;
	}
	else
	{
		folder.style.display = "block";
	}
}
TOCTree.prototype.isRootFolder = function ( folder )
{
	if ( isNav4 )
	{
		return (this.m_nXOffset == folder.left);
	}
	else
	{
		return (0 == parseInt( folder.className.slice(1) ));
	}
}	// isRootFolder
/*
TOCTree.prototype.onDocClick = function ( e )
{
	var e = e ? e : this.m_winTOC.event;
	var evtTarget = e.srcElement ? e.srcElement : e.target ;

	// in Nav6 the target is a 'Text Node' - we want it's parent <A> node
	evtTarget = getParentByTagName( evtTarget, "A" );
	// clicking a link/<A> element?
	if ( evtTarget && evtTarget.href )
	{

		// is the href one of out tree TOCTree.prototype.s = function?
		var pos = evtTarget.href.search( /(si|tf|toggleAll)\(/ );
		if ( -1 != pos )
		{
			eval( "this." + evtTarget.href.slice( pos ) );
			return cancelEvent( e );
		}
	}
	if ( this.m_origClickHandler )
	{
		return this.m_origClickHandler( e );
	}
	if ( isNav4 )
		this.m_docTOC.routeEvent( e );
	return true ;
}	
*/
TOCTree.prototype.onDocKeyDown = function ( e )
{
	var keyCode = ( isIE ? this.m_winTOC.event.keyCode : e.which );
	if ( isNav4 )
	{
		// no support for arrow keys
		// so map the +[]' keys to up,left,right,and down keys, respectivly
		switch( keyCode )
		{
			case 39: keyCode = 40; break;
			case 91: keyCode = 37; break;
			case 93: keyCode = 39; break;
			case 61: keyCode = 38; break;
		}
	}

	var bOurKey = true ;
	var folder = this.getFolderFromID( 'z' + this.m_curFolderID );
	if ( ! folder )
	{
		bOurKey = false;
	}
	else
	{
		var iter = new FolderIter( folder );
		switch( keyCode )
		{
			case 38:

				// get the previous folder that's visible
				var prevFolder = iter.getPrev();
				while ( prevFolder )
				{
					if ( this.isFolderVisible( prevFolder ) )
					{
						break;
					}
					prevFolder = iter.getPrev();
				}
				this.selectFolder( prevFolder );
				break;
			case 40:

				// get the next folder that's visible
				var nextFolder = iter.getNext();
				while ( nextFolder )
				{
					if ( this.isFolderVisible( nextFolder ) )
					{
						break;
					}
					nextFolder = iter.getNext();
				}
				this.selectFolder( nextFolder );
				break;
			case 37:

				// if the folder is open, close it
				if ( this.isFolderOpen( folder ) )
				{
					this.tf( null, folder );
					if ( ! isNav4 )
					{
						var link = this.getFolderLink( folder );
						if ( link && link.href )
						{
							link.focus();
						}
					}
				}
				else	// select the parent
				{
					this.selectFolder( iter.getParent() );
				}
				break;
			case 39:

				// if the folder is closed, open it
				if ( this.isFolderClosed( folder ) )
				{
					this.tf( null, folder );
					if ( ! isNav4 )
					{
						var link = this.getFolderLink( folder );
						if ( link && link.href )
						{
							link.focus();
						}
					}
				}
				else	// select the first child
				{
					this.selectFolder( iter.getNextChild() );
				}
				break;
			default:

				bOurKey = false ;
				break;
		}
	}
	if ( bOurKey )
	{
		return cancelEvent( e );
	}
	else
	{
		if ( this.m_origKeyDownHandler )
		{
			return this.m_origKeyDownHandler( e );
		}
		if ( isNav4 )
			this.m_docTOC.routeEvent( e );
		return true ;
	}
}	
TOCTree.prototype.onDocKeyPress = function ( e )
{
	if ( ! isMoz5 ) return true;
	var keyCode = e.keyCode;
	var bOurKey = false ;
	switch( keyCode )
	{
		case 37:
		case 38:
		case 39:
		case 40:
			bOurKey = true ;
			break;
		default:
			break;
	}
	if ( bOurKey )
	{
		return cancelEvent( e );
	}
	else
	{
		if ( this.m_origKeyPressHandler )
		{
			return this.m_origKeyPressHandler( e );
		}
		return true ;
	}
}	
// toggleFolder
TOCTree.prototype.tf = function ( folderID, folder, nForce, bNoHilite )
{
	if ( ! this.m_bInitialized ) return ;
	// add "z" prefixes to ordinal IDs
	if ( parseInt( folderID ) == folderID )
	{
		folderID = 'z' + folderID;
	}
	if ( ! folder ) folder = this.getFolderFromID( folderID );
	if ( ! folder ) return ;
	if ( ! folderID ) folderID = folder.id ;
	var fForceClose = false;
	var fForceOpen = false;
	if ( nForce == 1 )
	{
		fForceOpen = true;
	}
	else if ( nForce == -1 )
	{
		fForceClose = true;
	}

	var fShow ;
	if ( this.isFolderOpen( folder ) || fForceClose )
	{
		fShow = false ;
		this.closeFolder( folder );
	}
	else
	{
		fShow = true ;
		this.openFolder( folder );
	}
	var iter = new FolderIter( folder );
	if ( isNav4 )
	{
		var fKeepToggling = true ;
		var	startY, exposedHeight = 0;
		var folderHeight = folder.clip.height ;
		var startHeight = ( folder.top + folderHeight );
		var nextY = startHeight;
		folder = iter.getNext();
		while( folder )
		{
			if ( fKeepToggling )
			{
				if ( iter.startLevel() >= iter.curLevel() )
				{
					fKeepToggling = false ;
				}
				else
				{
					if ( ! fShow )
					{
						this.hideFolder( folder );
						if ( this.isFolderOpen( folder ) )
							this.closeFolder( folder );
					}
					else if ( (iter.startLevel() + this.m_nIndentDelta) == iter.curLevel() )
					{
						// if opening a folder only expose the next level of sub folders 
						this.showFolder( folder );
					}
				}
			}
			if ( folder.visibility != "hide" )
			{
				folder.top = nextY ;
				exposedHeight += folder.clip.height ;
				nextY = folder.top + folder.clip.height ;
			}
			folder = iter.getNext();
		}
		//force scrollbars to hide/show
		this.m_docTOC.height = startHeight + exposedHeight + folderHeight ;
	}
	else
	{
		// toggle display of all children of this folder
		folder = iter.getNextChild();
		while( folder )
		{
			if ( !fShow )
			{
				this.hideFolder( folder );
				if ( this.isFolderOpen( folder ) )
					this.closeFolder( folder );
			}
			else if ( iter.curLevel() == (iter.startLevel() + 1) )
			{
				this.showFolder( folder );
			}
			folder = iter.getNextChild();
		}
	}
	//
	//	in case we hid the currently hilited folder, or, revealed it, or moved it - 
	//	hilite it again
	//
	if ( !bNoHilite )
	{
		this.hiliteFolder( this.getFolderFromID( 'z' + this.m_curFolderID ) );
	}
}	// toggleFolder
TOCTree.prototype.toggleAll = function ( fShow, toggleDepth )
{
	if ( ! this.m_bInitialized ) return ;

 	// start with folder "z0"
	var folder = this.getFolderFromID( "z0" );
	var iter = new FolderIter( folder );
	var level, isOpen;
	while ( folder )
	{
		if ( ! this.isLeafFolder( folder ) )
		{
			isOpen = this.isFolderOpen( folder );
			if ( (toggleDepth == null) || (toggleDepth < 0) )
			{
				if ( fShow )
				{
					// open folder if not already open
					if ( ! isOpen )
					{
						this.tf( folder.id, folder, 1, 1 );
					}
				}
				else if ( isOpen )
				{
					this.tf( folder.id, folder, -1, 1 );
				}
			}
			else	// if we're toggling above or below a certain depth
			{
				level = getFolderLevel( folder );
				if ( isNav4 ) // normalize to level 0,1,2, etc...
				{
					level = (level - this.m_nXOffset) / this.m_nIndentDelta ;
				}
				if ( fShow )
				{
					// if the folder level is > toggleDepth then
					// close the folder or, if the level is <= toggleDepth
					// then open it 
					if ( (!isOpen) && (level <= toggleDepth) )
					{
						this.tf( folder.id, folder, 1, 1 );
					}
					else if ( isOpen && (level > toggleDepth) )
					{
						this.tf( folder.id, folder, -1, 1 );
					}
				}
				else
				{
					if ( isOpen && (level >= toggleDepth) )
					{
						this.tf( folder.id, folder, -1, 1 );
					}
					else if ( (!isOpen) && (level < toggleDepth) )
					{
						this.tf( folder.id, folder, 1, 1 );
					}
				}
			}
		}
		folder = iter.getNext();
	}
	// we turned off highliting while toggling so...
	this.hiliteFolder( this.getFolderFromID( 'z' + this.m_curFolderID ) );

}	// toggleAll ()

// showItem
TOCTree.prototype.si = function ( href, bExposeFolder )
{

	if ( ! href ) return ;
	// seperate out the parent folderid
	var a = href.split( ":" );
	var folderId = a[ 1 ];
 	if ( folderId != null )
	{
		var folder = this.getFolderFromID( "z" + folderId );
		if ( bExposeFolder ) 
			this.exposeFolder( folder );
 		this.hiliteFolder( folder );
		this.m_curFolderID = folderId ;
	}
	if ( a[ 0 ] )
	{
		var newPath = this.m_basePath + a[ 0 ];
		if ( isMoz5 )
		{

			// first get the content window's location obj
			var l = this.m_winContent.location;
			if ( ! l.pathname )
			{
				// or use the TOC window's if the content window location
				// is not set
				l = this.m_winTOC.location;
			}
			//replace the href's filename with our own
			newPath = l.href.replace( /[^\\\/]*$/, newPath );
		}
		this.m_winContent.location = newPath;
		this.m_curBODYLocation = a[ 0 ];
	}
}	// si ()
TOCTree.prototype.selectFolder = function ( folder )
{

	if ( ! folder ) return;
	var link = this.getFolderLink( folder );
	if ( ! (link && link.href) )
	{
	 return ;	
	}
	var href = link.href;
	var pos = href.search( /[\/\\][^\/\\]*$/ );
	if ( -1 != pos )
	{
		href = href.slice( pos + 1 );
	}
	if ( href && 
		(-1 != href.search( /(si|tf|toggleAll)\(/ )) &&
		(-1 == href.search( /javascript/i )) )
	{

		eval( "this." + href );
		if ( !isNav4 )
		{
			link.focus();
		}
	}
}
TOCTree.prototype.getFolderLink = function ( folder, linkIndex )
{
	if ( !folder ) return "" ;
	var links = (isNav4 ? folder.document.links : getTags( folder, "A" ) );
	if ( !links ) return "" ;

	// skip the first link - its a link to the icon image click code
	if ( !linkIndex ) linkIndex = 1;

	return links[ linkIndex ];
}	// getFolderLink
TOCTree.prototype.lookUpHREFID = function ( href )
{
	if ( ! (href && this.m_ContentHREFToTOCLinkMap) ) return null;
	var id = this.m_ContentHREFToTOCLinkMap[ href ];
	if ( null == id )
	{
		// split href into path and anchorName
		var path = href;
		var anchorName = "";
		var aTmp = href.split( /#/ );
		if ( aTmp && aTmp[ 1 ] )
		{
			path = aTmp[0];
			anchorName = aTmp[1];
		}

		// search backwards along the node tree until an <A> element is found 
		// that is in the m_ContentHREFToTOCLinkMap
		if ( isW3C && anchorName )
		{
			var MAX_NODE_SEARCH = 10;
			var anchor = getElem( anchorName, this.m_winContent.document );
			if ( anchor && ("A" == anchor.tagName) )
			{
				var searchCount = 0;
				anchor = (anchor.previousSibling ? anchor.previousSibling : anchor.parentNode);
				while ( anchor && (searchCount < MAX_NODE_SEARCH) )
				{
					if ( (1 == anchor.nodeType) && 
						 ("A" == anchor.tagName) &&
						 anchor.getAttribute("Name") )
					{
						id = this.m_ContentHREFToTOCLinkMap[ path + "#" + anchor.getAttribute("Name") ];
						if ( id ) 
						{
							break;
						}
					}

					// if we've run out of siblings, look farther up the parent chain
					anchor = (anchor.previousSibling ? anchor.previousSibling : anchor.parentNode);
					searchCount++;
				}
			}
		}
		if ( null == id )
		{
			// try stripping off the #bookmark to find the start of the chapter
			id = this.m_ContentHREFToTOCLinkMap[ path ];
		}
	}
	return id ;

}	// lookUpHREFID
TOCTree.prototype.syncTOC = function ()
{
	// get the location of the BODY frame
	var newLoc = this.m_winContent.location.pathname + this.m_winContent.location.hash;
	//strip off the path
	var pos = newLoc.search( /[\/\\][^\/\\]*$/ );
	if ( -1 != pos )
	{
		newLoc = newLoc.slice( pos + 1 );
	}
	if ( newLoc != this.m_curBODYLocation )
	{
		this.m_curBODYLocation = newLoc ;
		// look up folderID
		var id = this.lookUpHREFID( newLoc );
		if ( id != null )
		{

			var folder = this.getFolderFromID( "z" + id );
			if ( folder )
			{
				this.exposeFolder( folder );
				this.hiliteFolder( folder );
				this.m_curFolderID = id ;
			}
		}
	}
	this.m_syncTimeoutId = this.m_winTOC.setTimeout( "TheTOCTree.syncTOC()", this.m_nSyncInterval );
}	// syncTOC
TOCTree.prototype.getFolderFromID = function ( folderID )
{
	return getElem( folderID, this.m_docTOC );
}
function FolderIter ( startFolder )
{
	this.m_startFolder = startFolder;
	this.m_curFolder = startFolder;
	this.m_startLevel = this.m_curLevel = getFolderLevel( startFolder );
	return this ;
}	// FolderIter
FolderIter.prototype.startFolder = function ()
{
	return this.m_startFolder ;
}
FolderIter.prototype.curFolder = function ()
{
	return this.m_curFolder ;
}
FolderIter.prototype.startLevel = function ()
{
	return this.m_startLevel ;
}
FolderIter.prototype.curLevel = function ()
{
	return this.m_curLevel ;
}
FolderIter.prototype.getNext = function ()
{
	if ( ! this.m_curFolder ) return null;
	var folder;
	if ( ! isIE4 )
	{
		folder = ( isNav4 ? this.m_curFolder.above : this.m_curFolder.nextSibling );
		while ( folder )
		{
			if ( isFolder( folder ) )
			{
				break;
			}
			folder = ( isNav4 ? folder.above : folder.nextSibling );
		}
	}
	else	// isIE4
	{
		for ( var i = this.m_curFolder.sourceIndex + 1; i < all.length; i++ )
		{
			folder = all[ i ];
			if ( isFolder( folder ) )
			{
				break ;
			}
		}
	}
	if ( folder )
		this.m_curLevel = getFolderLevel( folder );
	return this.m_curFolder = folder;
}	// FolderIter.prototype.getNext
FolderIter.prototype.getPrev = function ()
{
	if ( ! this.m_curFolder )
	{
		return null;
	}
	var folder;
	if ( ! isIE4 )
	{
		folder = ( isNav4 ? this.m_curFolder.below : this.m_curFolder.previousSibling );
		while ( folder )
		{
			if ( isFolder( folder ) )
			{
				break;
			}
			folder = ( isNav4 ? folder.below : folder.previousSibling );
		}
	}
	else	// isIE4
	{
		for ( var i = this.m_curFolder.sourceIndex-1; i >= 0; i-- )
		{
			folder = all[ i ];
			if ( isFolder( folder ) )
			{
				break ;
			}
		}
	}
	if ( folder )
		this.m_curLevel = getFolderLevel( folder );
	return this.m_curFolder = folder;
}	// FolderIter.prototype.getPrev
FolderIter.prototype.getParent = function ()
{
	var level ;
	var iter = new FolderIter( this.m_curFolder );
	var folder = iter.getPrev();
	while ( folder )
	{
		level = getFolderLevel( folder );
		if ( level < this.m_curLevel )
		{
			break;
		}
		folder = iter.getPrev();
	}
	this.m_curLevel = level;
	return this.m_curFolder = folder;
}	// FolderIter.prototype.getParent
FolderIter.prototype.getNextSibling = function ()
{
	var level ;
	var iter = new FolderIter( this.m_curFolder );
	var folder = iter.getNext();
	while ( folder )
	{
		level = getFolderLevel( folder );
		if ( this.m_curLevel == level )
		{
			break ;
		}
		else if ( this.m_curLevel > level )
		{
			folder = null;
			break ;
		}
		folder = iter.getNext();
	}
	this.m_curLevel = level;
	return this.m_curFolder = folder;
}	// FolderIter.prototype.getNextSibling
// actually child or grand child or grand grand child etc.
FolderIter.prototype.getNextChild = function ()
{
	if ( ! this.m_curFolder ) return null;
	var iter = new FolderIter( this.m_curFolder );
	var folder = iter.getNext();
	var level = iter.curLevel();
	this.m_curFolder = (this.m_startLevel < level ? folder : null);
	this.m_curLevel = level;
	return this.m_curFolder ;
}	// FolderIter.prototype.getNextChild
//FolderIter.isFolder = function ( folder )
function isFolder ( folder )
{
	if ( null == folder ) return false ;
	if ( isNav4 )
	{
		return ( "z" == folder.name.charAt( 0 ) );
	}
	else
	{
		return ( folder.tagName && 
			    (folder.tagName == "DIV") &&
		        ("z" == folder.id.charAt(0)) );
	}
}	// isFolder
function getFolderLevel ( folder )
{
	return ( 
		isNav4 ?
		folder.left :
		parseInt( folder.className.slice(1) ) );
}

